2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: Mac\040OS\040Test\040Responder.c,v $
26 Revision 1.17 2003/08/14 02:19:54 cheshire
27 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
29 Revision 1.16 2003/08/12 19:56:24 cheshire
34 #include <stdio.h> // For printf()
35 #include <string.h> // For strlen() etc.
37 #include <Events.h> // For WaitNextEvent()
38 #include <SIOUX.h> // For SIOUXHandleOneEvent()
40 #include "mDNSClientAPI.h" // Defines the interface to the client layer above
42 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
44 // These don't have to be globals, but their memory does need to remain valid for as
45 // long as the search is going on. They are declared as globals here for simplicity.
47 static mDNS_PlatformSupport p
;
48 static ServiceRecordSet p1
, p2
, afp
, http
, njp
;
49 static AuthRecord browsedomain
;
51 // This sample code just calls mDNS_RenameAndReregisterService to automatically pick a new
52 // unique name for the service. For a device such as a printer, this may be appropriate.
53 // For a device with a user interface, and a screen, and a keyboard, the appropriate
54 // response may be to prompt the user and ask them to choose a new name for the service.
55 mDNSlocal
void Callback(mDNS
*const m
, ServiceRecordSet
*const sr
, mStatus result
)
59 case mStatus_NoError
: debugf("Callback: %##s Name Registered", sr
->RR_SRV
.resrec
.name
.c
); break;
60 case mStatus_NameConflict
: debugf("Callback: %##s Name Conflict", sr
->RR_SRV
.resrec
.name
.c
); break;
61 case mStatus_MemFree
: debugf("Callback: %##s Memory Free", sr
->RR_SRV
.resrec
.name
.c
); break;
62 default: debugf("Callback: %##s Unknown Result %d", sr
->RR_SRV
.resrec
.name
.c
, result
); break;
65 if (result
== mStatus_NameConflict
) mDNS_RenameAndReregisterService(m
, sr
, mDNSNULL
);
68 // RegisterService() is a simple wrapper function which takes C string
69 // parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
70 mDNSlocal
void RegisterService(mDNS
*m
, ServiceRecordSet
*recordset
,
71 UInt16 PortAsNumber
, const char txtinfo
[],
72 const domainlabel
*const n
, const char type
[], const char domain
[])
80 port
.b
[0] = (UInt8
)(PortAsNumber
>> 8);
81 port
.b
[1] = (UInt8
)(PortAsNumber
);
82 MakeDomainNameFromDNSNameString(&t
, type
);
83 MakeDomainNameFromDNSNameString(&d
, domain
);
87 strncpy((char*)txtbuffer
+1, txtinfo
, sizeof(txtbuffer
)-1);
88 txtbuffer
[0] = (UInt8
)strlen(txtinfo
);
93 mDNS_RegisterService(m
, recordset
,
94 n
, &t
, &d
, // Name, type, domain
95 mDNSNULL
, port
, // Host and port
96 txtbuffer
, (mDNSu16
)(1+txtbuffer
[0]), // TXT data, length
97 mDNSNULL
, 0, // Subtypes (none)
98 mDNSInterface_Any
, // Interace ID
99 Callback
, mDNSNULL
); // Callback and context
101 ConvertDomainNameToCString(&recordset
->RR_SRV
.resrec
.name
, buffer
);
102 printf("Made Service Records for %s\n", buffer
);
105 // RegisterFakeServiceForTesting() simulates the effect of services being registered on
106 // dynamically-allocated port numbers. No real service exists on that port -- this is just for testing.
107 mDNSlocal
void RegisterFakeServiceForTesting(mDNS
*m
, ServiceRecordSet
*recordset
, const char txtinfo
[],
108 const char name
[], const char type
[], const char domain
[])
110 static UInt16 NextPort
= 0xF000;
112 MakeDomainLabelFromLiteralString(&n
, name
);
113 RegisterService(m
, recordset
, NextPort
++, txtinfo
, &n
, type
, domain
);
116 // CreateProxyRegistrationForRealService() checks to see if the given port is currently
117 // in use, and if so, advertises the specified service as present on that port.
118 // This is useful for advertising existing real services (Personal Web Sharing, Personal
119 // File Sharing, etc.) that currently don't register with mDNS Service Discovery themselves.
120 mDNSlocal OSStatus
CreateProxyRegistrationForRealService(mDNS
*m
, UInt16 PortAsNumber
, const char txtinfo
[],
121 const char *servicetype
, ServiceRecordSet
*recordset
)
127 TEndpointInfo endpointinfo
;
128 EndpointRef ep
= OTOpenEndpoint(OTCreateConfiguration(kTCPName
), 0, &endpointinfo
, &err
);
129 if (!ep
|| err
) { printf("OTOpenEndpoint (CreateProxyRegistrationForRealService) failed %d", err
); return(err
); }
131 port
.b
[0] = (UInt8
)(PortAsNumber
>> 8);
132 port
.b
[1] = (UInt8
)(PortAsNumber
);
133 ia
.fAddressType
= AF_INET
;
134 ia
.fPort
= port
.NotAnInteger
;
136 bindReq
.addr
.maxlen
= sizeof(ia
);
137 bindReq
.addr
.len
= sizeof(ia
);
138 bindReq
.addr
.buf
= (UInt8
*)&ia
;
140 err
= OTBind(ep
, &bindReq
, NULL
);
142 if (err
== kOTBadAddressErr
)
143 RegisterService(m
, recordset
, PortAsNumber
, txtinfo
, &m
->nicelabel
, servicetype
, "local.");
145 debugf("OTBind failed %d", err
);
151 // Done once on startup, and then again every time our address changes
152 mDNSlocal OSStatus
mDNSResponderTestSetup(mDNS
*m
)
155 mDNSv4Addr ip
= m
->HostInterfaces
->ip
.ip
.v4
;
157 ConvertDomainNameToCString(&m
->hostname
, buffer
);
158 printf("Name %s\n", buffer
);
159 printf("IP %d.%d.%d.%d\n", ip
.b
[0], ip
.b
[1], ip
.b
[2], ip
.b
[3]);
162 printf("Registering Service Records\n");
163 // Create example printer discovery records
164 //static ServiceRecordSet p1, p2;
168 RegisterFakeServiceForTesting(m
, &p1
, "path=/index.html", "Web Server One", "_http._tcp.", "local.");
169 RegisterFakeServiceForTesting(m
, &p2
, "path=/path.html", "Web Server Two", "_http._tcp.", "local.");
171 RegisterFakeServiceForTesting(m
, &p1
, "rn=lpq1", "Epson Stylus 900N", "_printer._tcp.", "local.");
172 RegisterFakeServiceForTesting(m
, &p2
, "rn=lpq2", "HP LaserJet", "_printer._tcp.", "local.");
174 RegisterFakeServiceForTesting(m
, &p1
, "rn=lpq3", "My Printer", "_printer._tcp.", "local.");
175 RegisterFakeServiceForTesting(m
, &p2
, "lrn=pq4", "My Other Printer", "_printer._tcp.", "local.");
178 // If AFP Server is running, register a record for it
179 CreateProxyRegistrationForRealService(m
, 548, "", "_afpovertcp._tcp.", &afp
);
181 // If Web Server is running, register a record for it
182 CreateProxyRegistrationForRealService(m
, 80, "", "_http._tcp.", &http
);
184 // And pretend we always have an NJP server running on port 80 too
185 //RegisterService(m, &njp, 80, "NJP/", &m->nicelabel, "_njp._tcp.", "local.");
187 // Advertise that apple.com. is available for browsing
188 mDNS_AdvertiseDomains(m
, &browsedomain
, mDNS_DomainTypeBrowse
, mDNSInterface_Any
, "IL 2\\4th Floor.apple.com.");
193 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
194 mDNSlocal Boolean
YieldSomeTime(UInt32 milliseconds
)
196 extern Boolean SIOUXQuitting
;
198 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
199 SIOUXHandleOneEvent(&e
);
200 return(SIOUXQuitting
);
205 extern void mDNSPlatformIdle(mDNS
*const m
); // Only needed for debugging version
207 Boolean DoneSetup
= false;
209 SIOUXSettings
.asktosaveonclose
= false;
210 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Responder";
212 printf("Prototype Multicast DNS Responder\n\n");
213 printf("WARNING! This is experimental software.\n\n");
214 printf("Multicast DNS is currently an experimental protocol.\n\n");
215 printf("This software reports errors using MacsBug breaks,\n");
216 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
217 printf("******************************************************************************\n");
219 err
= InitOpenTransport();
220 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
222 err
= mDNS_Init(&m
, &p
, mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
223 mDNS_Init_AdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
224 if (err
) return(err
);
226 while (!YieldSomeTime(35))
228 // For debugging, use "#define __ONLYSYSTEMTASK__ 1" and call mDNSPlatformIdle() periodically.
229 // For shipping code, don't define __ONLYSYSTEMTASK__, and you don't need to call mDNSPlatformIdle()
230 mDNSPlatformIdle(&m
); // Only needed for debugging version
231 if (m
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
234 printf("\nListening for mDNS queries...\n");
235 mDNSResponderTestSetup(&m
);
239 if (p1
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &p1
);
240 if (p2
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &p2
);
241 if (afp
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &afp
);
242 if (http
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &http
);
243 if (njp
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &njp
);